package com.sise.Backtracking;

import java.util.ArrayList;
import java.util.List;

/**
 *      46. 全排列
 *      给定一个 没有重复 数字的序列，返回其所有可能的全排列。
 *      输入: [1,2,3]
 *      输出:
 *      [
 *          [1,2,3],
 *          [1,3,2],
 *          [2,1,3],
 *          [2,3,1],
 *          [3,1,2],
 *          [3,2,1]
 *      ]
 */
public class _46_permute {

    // 这道题和 Backtracking 是一样的，只不过这里将 res 向下传递
    public List<List<Integer>> permute(int[] nums) {
        int len = nums.length;
        // 使用一个动态数组保存所有可能的全排列
        List<List<Integer>> res = new ArrayList<>();
        if (len == 0) {
            return res;
        }

        // 使用 used 是因为在 for 循环中，自己不能包含自己
        boolean[] used = new boolean[len];
        List<Integer> path = new ArrayList<>();

        dfs(nums, path, used, res);
        return res;
    }

    private void dfs(int[] nums, List<Integer> path, boolean[] used, List<List<Integer>> res) {

        // 设置结束条件
        if (path.size() == nums.length) {
            res.add(path);
            return;
        }

        // 路径：记录在 path
        // 选择列表：nums 中不存在的 path 元素
        // 结束条件：nums 中的元素全部添加到 path 中
        for (int i = 0; i < nums.length; i++) {

            // 这里使用了 used[] 数组，而不是使用 List 等其他列表，可以节省时间复杂度
            if (!used[i]) {
                path.add(nums[i]);
                used[i] = true;

                dfs(nums, path, used, res);
                // 注意：下面这两行代码发生 「回溯」，回溯发生在从 深层结点 回到 浅层结点 的过程，代码在形式上和递归之前是对称的
                used[i] = false;
                path.remove(path.size() - 1);
            }
        }
    }
}
